package com.sky.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.entity.Setmeal;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.mapper.DishFlavorMapper;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealDishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.result.PageResult;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author bairimengchang
 * @version 1.0
 * @project sky-take-out
 * @description 菜品管理业务接口实现类
 * @date 2024/08/08 11:26:32
 */
@Service
@Slf4j
public class DishServiceImpl implements DishService {

    @Autowired
    private DishMapper dishMapper;

    @Autowired
    private DishFlavorMapper dishFlavorMapper;

    @Autowired
    private SetmealDishMapper setmealDishMapper;

    @Autowired
    private SetmealMapper setmealMapper;

    /**
     * 新增菜品
     * @param dishDTO 菜品数据传输数据模型
     * @return 新增操作是否成功，返回 true 表示成功，false 表示失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addDish(DishDTO dishDTO) {

        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO, dish);
        //默认是禁用的，不展示给用户
        dish.setStatus(StatusConstant.DISABLE);

        int insert = dishMapper.insertSelective(dish);

        List<DishFlavor> dishFlavors = dishDTO.getFlavors();
        //插入口味数据
        if (dishFlavors != null && !dishFlavors.isEmpty()){
            //有口味对象数据
            dishFlavors.forEach(dishFlavor -> {
                //都取出来加上这个口味对应的菜品id
                dishFlavor.setDishId(dish.getId());
            });
            //批量插入，因为一个菜品有多个口味
            log.info("即将插入数据库的口味数据:{}", dishFlavors);
            int insertBatch = dishFlavorMapper.insertBatch(dishFlavors);
        }

        return insert == 1;
    }

    /**
     * 菜品分页查询
     * @param dishPageQueryDTO 菜品分页查询时传递的数据模型
     * @return 分页查询结果
     */
    @Override
    public PageResult getDishPage(DishPageQueryDTO dishPageQueryDTO) {
        PageResult pageResult = new PageResult();

        //这个时候就告诉插件要做拦截sql了
        PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());

        //在大多数分页插件中，影响的是当前“线程”中的所有查询语句
        //如果你想要在一个请求/线程中执行多个不同的分页查询，你通常需要在每次分页查询之后重置分页状态。
        //例如，调用 PageHelper.clearPage() 可以清除当前线程的分页状态。
        //如果不进行重置，所有后续的分页查询都将受到之前设置的分页参数的影响。

        //注意这里返回的是VO，因为要额外查询到分类名称字段name，需要多表连接
        List<DishVO> dishList = dishMapper.selectByPageQuery(dishPageQueryDTO);
        log.info("查询到的菜品数据：{}", dishList);
        //不能查询到每个菜品的口味信息，因为参数没有给菜品编号
        PageInfo<DishVO> pageInfo = new PageInfo<>(dishList);
        pageResult.setTotal(pageInfo.getTotal());
        pageResult.setRecords(pageInfo.getList());

        return pageResult;
    }

    /**
     * 修改菜品起售、停售状态
     * @param status 菜品售卖状态
     * @param id 要修改售卖状态的菜品id
     * @return 新增操作是否成功，返回 true 表示成功，false 表示失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeDishStatus(Integer status, Long id) {
        //想要让菜品失效时，需要把包含此菜品的套餐失效
        if (Objects.equals(status, StatusConstant.DISABLE)){
            //如果要将菜品禁用，去查询含有这个菜品的所有套餐信息，把套餐信息先禁用了
            //先去查询菜品所属套餐的id
            List<Long> SetmealIds = setmealDishMapper.selectSetmealIdsByDishId(id);
            if (SetmealIds != null && !SetmealIds.isEmpty()){
                for (Long setmealId : SetmealIds){
                    //查询这个套餐的详细信息，设置为禁用状态
                    Setmeal setmeal = setmealMapper.selectByPrimaryKey(setmealId);
                    setmeal.setStatus(StatusConstant.DISABLE);
                    log.info("被禁用的套餐信息:{}", setmeal.getName());
                    //禁用
                    int update = setmealMapper.updateByPrimaryKeySelective(setmeal);
                }
            }
        }
        //禁用或不禁用套餐信息后，再去修改菜品售卖状态
        Dish dish = new Dish();
        dish.setStatus(status);
        dish.setId(id);
        int update = dishMapper.updateByPrimaryKeySelective(dish);
        return update == 1;
    }

    /**
     * 根据id查询菜品
     * @param id 要查询的菜品的id
     * @return 符合查询条件的菜品视图对象
     */
    @Override
    public DishVO getDishById(Long id) {
        Dish dish = dishMapper.selectByPrimaryKey(id);
        DishVO dishVO = new DishVO();

        //如果此时并没有合适的dish对象（返回一个空的对象），会报错IllegalArgumentException，因此去写一个全局异常处理器
        BeanUtils.copyProperties(dish, dishVO);

        //额外设置下口味对象，之所以是List，是因为一个菜品可以有多种口味对象，比如同时有辣度和咸度
        List<DishFlavor> dishFlavorList = dishFlavorMapper.selectByDishId(dish.getId());
        dishVO.setFlavors(dishFlavorList);
        log.info("dishVO内容:{}", dishVO);

        return dishVO;
    }

    /**
     * 修改菜品
     * @param dishDTO 菜品数据传输数据模型
     * @return 修改操作是否成功，返回 true 表示成功，false 表示失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean changeDish(DishDTO dishDTO) {
        // TODO 可以加上对dishId的判断
        Dish dish = new Dish();
        BeanUtils.copyProperties(dishDTO, dish);

        //修改口味
        //先删除原有的口味对象不管原来这个菜品有没有，直接删除
        dishFlavorMapper.deleteByDishId(dish.getId());

        //再添加新的口味对象
        List<DishFlavor> dishFlavors = dishDTO.getFlavors();
        if (dishFlavors != null && !dishFlavors.isEmpty()){
            //有口味对象数据
            dishFlavors.forEach(dishFlavor -> {
                //都取出来加上这个口味对应的菜品id
                dishFlavor.setDishId(dish.getId());
            });
            //批量插入，因为一个菜品有多个口味
            int insertBatch = dishFlavorMapper.insertBatch(dishFlavors);
        }

        int update = dishMapper.updateByPrimaryKeySelective(dish);
        return update == 1;
    }

    /**
     * 根据分类id查询菜品
     * @param categoryId 分类id
     * @return 该分类id下的所有菜品的结果对象
     */
    @Override
    public List<Dish> getByCategoryId(Long categoryId) {
        return dishMapper.selectDishByCategoryId(categoryId);
    }

    /**
     * 批量删除菜品
     * @param ids 菜品id，之间用逗号分隔
     * @return 新增操作是否成功，返回 true 表示成功，false 表示失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeBatchDish(ArrayList<Long> ids) {
        //判断当前菜品是否能删除，状态不能是起售状态
        for (Long id : ids) {
            Dish dish = dishMapper.selectByPrimaryKey(id);
            if (Objects.equals(dish.getStatus(), StatusConstant.ENABLE)){
                //当前菜品还处在在售状态，不能删除
                throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
            }
        }

        //判断当前菜品是否被套餐关联
        List<Long> setmealIds = setmealDishMapper.selectSetmealIdsByDishIds(ids);
        if (setmealIds != null && !setmealIds.isEmpty()){
            //存在关联的套餐，不能删除
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }

        //删除菜品表中的菜品数据
        int deleteDish = dishMapper.deleteBatchDishByIds(ids);

        //删除菜品关联的口味数据(根据菜品id删除对应的口味数据)
        int deleteDishFlavor = dishFlavorMapper.deleteBatchDishFlavorByIds(ids);
        return deleteDish == ids.size();
    }

    /**
     * 根据分类id查询菜品视图对象列表（带口味）
     * @param categoryId 分类id
     * @return 菜品视图对象列表（带口味）
     */
    @Override
    public List<DishVO> getDishVOByCategoryId(Long categoryId) {

        //全部菜品
        List<Dish> dishAllList = dishMapper.selectDishByCategoryId(categoryId);
        //在售的
        List<Dish> dishList = new ArrayList<>();
        for (Dish dish : dishAllList){
            if (Objects.equals(dish.getStatus(), StatusConstant.ENABLE)){
                dishList.add(dish);
            }
        }

        //结果集对象
        List<DishVO> dishVOList = new ArrayList<>();

        for (Dish dish : dishList) {
            //每一个在售的菜品
            DishVO dishVO = new DishVO();
            BeanUtils.copyProperties(dish,dishVO);
            log.info("当前C端菜品视图信息:{}", dishVO);

            //根据菜品id查询对应的口味
            List<DishFlavor> dishFlavorList = dishFlavorMapper.selectByDishId(dish.getId());

            log.info("加上口味后的C端菜品视图信息:{}", dishVO);
            dishVO.setFlavors(dishFlavorList);
            dishVOList.add(dishVO);
        }

        return dishVOList;
    }
}
